#include <stdio.h>
#include <windows.h>
#include <limits.h>

/**
 * 打印数字的二进制原码补码反码
 * 	正数：原码、补码、反码是一样的
 * 	负数：
 * 		原码
 * 		反码：原码按位取反，符号位不变
 * 		补码：在反码的基础上加1
 *
 * 	负数的原码 => 补码 => 原码按位取反，符号位不变，再加1
 * 		-5 => 原码 1000 0101 => 反码 1111 1010 => 补码 1111 1011
 * 	负数的补码 => 原码 => 补码按位取反，符号位不变，再加1
 * 		-5 => 补码 1111 1011 => 反码 1000 0100 => 原码 1000 0101
 * 使用补码完美解决了下面几个问题：
 * 	1.对于数字0，+0和-0没有意义，如果用原码来表示的话，+0和-0分别是不同的二进制数字，0的表示就不唯一了，如果是用补码来表示的话，+0和-0的补码都是 0000 0000
 * 	2.将减法统一为加法，CPU只需要一个加法器电路就可以同时处理加法和减法运算，极大的简化了硬件设计
 * 	3.-128的补码是1000 0000，没有引入补码之前，这个值代表-0，引入补码后，补码系统规定 1000 0000 直接表示 -128
 * 	4.使用8个二进制位可以表示128个正数和128个负数，能表示的正数和负数的个数正好是相同的
 */

/**
 * 演示使用反码将减法统一为加法
 *   5 的二进制 => 原码 0000 0101 => 反码 0000 0101 => 补码 0000 0101
 *  												       +
 *  -1 的二进制 => 原码 1000 0001 => 反码 1111 1110 => 补码 1111 1111
 *
 *  运算结果									       => 补码 0000 0100 => 十进制的4
 */

void print_binary_string(int n)
{
	for(int i=7; i>=0; i--)
	{
		printf("%d", (n>>i) & 1);
	}
	printf("\n");
}

int main()
{
	int n = 5;
	// 打印5的二进制原码
	printf("5  的二进制原码  ");
	print_binary_string(n);
	// 打印5的二进制反码
	printf("5  的二进制反码  ");
	print_binary_string(n);
	// 打印5的二进制补码
	printf("5  的二进制补码  ");
	print_binary_string(n);

	printf("-----------------------\n");

	// 打印-5的二进制原码
	printf("-5 的二进制原码  ");
	print_binary_string((1 << 7) | n);
	// 打印-5的二进制反码
	printf("-5 的二进制反码  ");
	print_binary_string(~n);
	// 打印-5的二进制补码
	printf("-5 的二进制补码  ");
	print_binary_string(-n);

	/**
	 * 下面程序是死循环
	 * 	127 的二进制 => 原码 0111 1111 => 反码 0111 1111 => 补码 0111 1111
	 * 															+
	 * 	  1 的二进制 => 原码 0000 0001 => 反码 0000 0001 => 补码 0000 0001
	 *
	 * 	运算结果	  									    => 补码 1000 0000 => 十进制的-128（补码系统规定 1000 0000 直接表示 -128）
	 */
	/*
	for(char a = 0; a < 128; a++)
	{
		printf("%3d\n", a);
		Sleep(100);
	}
	*/

	/**
	 * 下面程序不是死循环
	 */
	/*
	for(unsigned char a = 0; a < 128; a++)
	{
		printf("%3d\n", a);
		Sleep(100);
	}
	*/

    printf("signed char 范围: %d 到 %d\n", SCHAR_MIN, SCHAR_MAX);
    printf("unsigned char 范围: 0 到 %u\n", UCHAR_MAX);
    printf("char 范围: %d 到 %d\n", CHAR_MIN, CHAR_MAX);
	return 0;
}
